package cn.piesat.client.utils;

import cn.piesat.client.model.FileRecordModel;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPFileFilters;
import org.apache.commons.net.ftp.FTPReply;
import org.springframework.stereotype.Component;

import java.io.*;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.regex.Pattern;

@Component
public class FTPUtil {

    /**
     * 判断文件是否已上传过，如果传过，文件大小，修改日期是否有变化。
     *
     * @param file  本地文件
     * @param store 已上传文件列表
     * @return true 已上传，false 待上传
     */
    public boolean check(File file, List<FileRecordModel> store) {

        boolean result = false;
        if (null != store && store.size() > 0) {
            String filepath = file.getPath();
            long size = file.length();
            long lastmodified = DateUtil.getInstance().getUTCDate(file.lastModified()).getTime() / 1000 * 1000;
            for (FileRecordModel model : store) {
                if (model.getFilePath().equals(filepath) && model.getSize() == size && model.getLastmodified().getTime() == lastmodified) {
                    result = true;
                    break;
                }
            }
        }
        return result;

    }

    /**
     * 获取FTPClient对象
     *
     * @param ftpHost     服务器IP
     * @param ftpPort     服务器端口号
     * @param ftpUserName 用户名
     * @param ftpPassword 密码
     * @return FTPClient
     */
    public FTPClient getFTPClient(String ftpHost, int ftpPort, String ftpUserName, String ftpPassword) {
        FTPClient ftp = null;
        try {
            ftp = new FTPClient();
            // 设置连接超时时间,5000毫秒
            ftp.setConnectTimeout(5000);
            // 连接FPT服务器,设置IP及端口
            ftp.connect(ftpHost, ftpPort);
            // 设置用户名和密码
            ftp.login(ftpUserName, ftpPassword);
            // 设置中文编码集，防止中文乱码
            ftp.setControlEncoding("UTF-8");
            if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
                System.out.println("cant connect FTP，user or password error");
                ftp.disconnect();
            } else {
                System.out.println("FTP connected");
            }
        } catch (SocketException e) {
            e.printStackTrace();
            System.out.println("FTP IP address error");
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("FTP Port error");
        }
        return ftp;
    }

    /**
     * 关闭FTP方法
     *
     * @param ftp
     * @return
     */
    public boolean closeFTP(FTPClient ftp) {
        try {
            ftp.logout();
        } catch (Exception e) {
            System.out.println("FTP close fail");
        } finally {
            if (ftp.isConnected()) {
                try {
                    ftp.disconnect();
                } catch (IOException ioe) {
                    System.out.println("FTP close fail");
                }
            }
        }
        return false;
    }

    public boolean uploadFile(FTPClient ftp, String filePath, String ftpPath) {
        // 设置PassiveMode传输
        ftp.enterLocalPassiveMode();
        // 设置二进制传输，使用BINARY_FILE_TYPE，ASC容易造成文件损坏
        try {
            ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 上传文件
        File file = new File(filePath);
        boolean flag = false;
        InputStream in = null;
        try {
            in = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        String tempName = ftpPath + "/" + file.getName();
        try {
            flag = ftp.storeFile(new String(tempName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1),
                    in);
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (flag) {
            System.out.println("upload successfully:" + filePath);
        } else {
            System.out.println("upload failed:" + filePath);
        }
        return flag;
    }


    public boolean uploadFiles(FTPClient ftp, String filePath, String ftpPath, String subPath,
                               String filenameRegx, List<FileRecordModel> store) {
        boolean flag = false;
        InputStream in = null;
        try {
            // 设置PassiveMode传输
            ftp.enterLocalPassiveMode();
            // 设置二进制传输，使用BINARY_FILE_TYPE，ASC容易造成文件损坏
            ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
            // 每次跳转到根目录
            ftp.changeWorkingDirectory("/");
            // 上传文件
            File file = new File(filePath);
            if (file.isDirectory()) {
                String dirPath = ftpPath;
                if (!subPath.equals("")) {
                    dirPath = ftpPath + "/" + subPath;
                }
                System.out.println("Upload Folder" + dirPath);
                String[] dirPathList = dirPath.split("/");
                for (String s : dirPathList) {
                    if (StringUtils.isNotBlank(s)) {
                        boolean succ = ftp.makeDirectory(s);
                        if (succ) {
                            System.out.println("folder:" + s + " createed");
                        }
                        // 跳转目标目录
                        ftp.changeWorkingDirectory(s);
                    }
                }
                File[] files = file.listFiles();
                for (int i = 0; i < files.length; i++) {
                    if (files[i].isDirectory()) {
                        uploadFiles(ftp, files[i].getAbsolutePath(), dirPath, files[i].getName(), filenameRegx, store);
                    } else {
                        uploadFiles(ftp, files[i].getAbsolutePath(), dirPath, "", filenameRegx, store);
                    }
                }
            } else {
                //文件名正则匹配
                if (Pattern.compile(filenameRegx).matcher(file.getName()).find()) {
//					if (Pattern.matches(filenameRegx,file.getName())) {
                    // 在上传文件前-先判断是否已经上传
                    if (!check(file, store)) {
                        in = new FileInputStream(file);
                        String tempName = ftpPath + "/" + file.getName();
                        flag = ftp.storeFile(new String(tempName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1),
                                in);
                        if (flag) {
                            System.out.println("upload successfully:" + filePath);
                            FileRecordModel dto = new FileRecordModel();
                            dto.setFilePath(file.getAbsolutePath());
                            dto.setSize(file.length());
                            dto.setLastmodified(DateUtil.getInstance().getUTCDate(file.lastModified()));
                            dto.setCreatetime(DateUtil.getInstance().getUTCDate());
                            store.add(dto);
                        } else {
                            System.out.println("upload failed:" + filePath);
                        }
                        in.close();
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            flag = false;
            System.out.println("upload failed");
        }

        return flag;
    }

    /**
     * FTP上传文件Dstdet
     *
     * @param ftp      FTP客户端
     * @param filePath 上传路径
     * @param ftpPath  目标路径
     * @return
     */
    public boolean uploadFolder(FTPClient ftp, String filePath, String ftpPath, String subPath,
                                String filterNameHas, String filterNamePattern) {
        boolean flag = false;
        InputStream in = null;
        try {
            // 设置PassiveMode传输
            ftp.enterLocalPassiveMode();
            // 设置二进制传输，使用BINARY_FILE_TYPE，ASC容易造成文件损坏
            ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
            // 每次跳转到根目录
            ftp.changeWorkingDirectory("/");
            // 上传文件

            File file = new File(filePath);

            if (file.isDirectory()) {
                String dirPath = ftpPath;
                if (!subPath.equals("")) {
                    dirPath = ftpPath + "/" + subPath;
                }
                System.out.println("Upload Folder" + dirPath);
                String[] dirPathList = dirPath.split("/");
                for (String s : dirPathList) {
                    if (StringUtils.isNotBlank(s)) {
                        boolean succ = ftp.makeDirectory(s);
                        if (succ) {
                            System.out.println("folder:" + s + " createed");
                        }
                        // 跳转目标目录
                        ftp.changeWorkingDirectory(s);
                    }
                }
                File[] files = file.listFiles();
                for (int i = 0; i < files.length; i++) {
                    if (files[i].isDirectory()) {
                        uploadFolder(ftp, files[i].getAbsolutePath(), dirPath, files[i].getName(), filterNameHas,
                                filterNamePattern);
                    } else {
                        if (files[i].getName().contains(filterNameHas)
                                && files[i].getName().endsWith(filterNamePattern)) {
                            // 在上传文件前-先判断是否已经存在 1
                            if (!sizeEqualFTPFile(files[i].getAbsolutePath(), ftp, dirPath)) {
                                uploadFolder(ftp, files[i].getAbsolutePath(), dirPath, "", filterNameHas,
                                        filterNamePattern);
                            }
                        }
                    }
                }
            } else {
                in = new FileInputStream(file);
                String tempName = ftpPath + "/" + file.getName();
                flag = ftp.storeFile(new String(tempName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1),
                        in);
                if (flag) {
                    System.out.println("upload successfully:" + filePath);
                } else {
                    System.out.println("upload failed:" + filePath);
                }
                in.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
            flag = false;
            System.out.println("upload failed");
        }
        return flag;
    }

    /**
     * 下载FTP下指定文件
     *
     * @param ftp       FTPClient对象
     * @param ftpPath   FTP下载的目标文件路径
     * @param localPath 下载保存的目录
     * @return
     */
    public boolean downLoadFTP(FTPClient ftp, String ftpPath,
                               String localPath, String filename_container, String filename_endwith) {
        // 默认失败
        boolean flag = false;
        try {
            // 跳转到文件目录
            ftp.changeWorkingDirectory(ftpPath);
//            // 获取目录下文件集合
            ftp.enterLocalPassiveMode();
            FTPFile[] ftpfiles = ftp.listFiles();
            for (FTPFile ftpfile : ftpfiles) {
                String ftptempPath = ftpPath + "/" + ftpfile.getName();
                ftp.changeWorkingDirectory(ftptempPath);
                ftp.enterLocalPassiveMode();
                String localPath_new = localPath + File.separator + ftpfile.getName().split("\\.")[0].replace("KTTFG", "");
                if (!new File(localPath_new).exists()) {
                    new File(localPath_new).mkdirs();
                }
                String localtempFile = localPath_new + File.separator + ftpfile.getName();
                System.out.println(localtempFile);
                if (ftpfile.isDirectory()) {
                    if (!new File(localtempFile).exists()) {
                        new File(localtempFile).mkdirs();
                    }
                    downLoadFTP(ftp, ftptempPath, localtempFile, filename_container, filename_endwith);
                } else {
                    if (ftpfile.getName().contains(filename_container) && ftpfile.getName().endsWith(filename_endwith)) {
                        //判断FTP目标文件夹大小和本地文件夹大小比较
                        Boolean aBoolean = sizeEqualLocalFile(localtempFile, ftpfile);
                        if (!aBoolean) {
                            //将上传的文件放入到输出流中
                            File downFile = new File(localtempFile);
                            System.out.println(downFile.getName() + " File donwload");
                            OutputStream out = new FileOutputStream(downFile);
                            // 绑定输出流下载文件,需要设置编码集，不然可能出现文件为空的情况
                            flag = ftp.retrieveFile(new String(ftpfile.getName().getBytes("UTF-8"), "ISO-8859-1"), out);
                            out.flush();
                            out.close();
                            if (flag) {
                                System.out.println("download success: " + downFile.getPath());
                            } else {
                                System.out.println("download fail: " + downFile.getPath());
                            }
                        }
                    }


                }
            }

        } catch (Exception e) {
            System.out.println("download fail");
        }
        return flag;
    }

    /**
     * 获取FTP指定的文件大小与本地目录作比较 ——是否直接上传
     *
     * @param filePath Lixun下的文件路径
     * @param ftpfile  FTP下的文件路径：全路径
     * @return
     */
    public Boolean sizeEqualLocalFile(String filePath, FTPFile ftpfile) {
        Boolean b = false;
        //获取FTP目标文件夹的大小
        try {

            //获取本地目标文件夹大小
            File file = new File(filePath);

            long ftptime = ftpfile.getTimestamp().getTime().getTime();
            if (file.exists()) {
                long localtime = file.lastModified();
                if (file.length() == ftpfile.getSize() && localtime > ftptime) {
                    b = true;
                } else {
                    System.out.println(file.getName() + " File need update!");
                }
            } else {
                System.out.println(file.getName() + " File noe exist!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return b;
    }

    /**
     * 获取FTP指定的文件大小与本地目录作比较 ——是否直接上传
     *
     * @param filePath   Lixun下的文件路径
     * @param ftp
     * @param folderPath FTP下的文件路径：全路径
     * @return
     */
    public Boolean sizeEqualFTPFile(String filePath, FTPClient ftp, String folderPath) {
        Boolean b = false;
        // 获取FTP目标文件夹的大小
        try {
            ftp.changeWorkingDirectory(new String(folderPath.getBytes("UTF-8"), "ISO-8859-1"));
            // 设置FTP连接模式
            ftp.enterLocalPassiveMode();
            // 获取本地目标文件夹大小
            File file = new File(filePath);
            // 获取指定目录下文件文件对象集合
            FTPFile files[] = ftp.listFiles(file.getName(), FTPFileFilters.ALL);
            if (null != files && files.length > 0) {
                if (file.length() == files[0].getSize()) {
                    b = true;
                }
            }

        } catch (IOException ex) {
            System.out.println(ex);
        }
        return b;
    }
}
